<?php
require_once('../../../config.php');

error_reporting(E_ALL ^ E_NOTICE);

class Chat {
	private $user;	// user object

	function __construct($user) {
		$this->user = $user;
	}

	function join($room) {
		$presence = new object();
		$presence->username = $this->user->username;
		$presence->room = $room;
		$presence->room_type = "groupchat";
		$presence->first_update = time();
		$presence->last_update = time();
		$presence->sesskey = $this->user->sesskey;

		insert_record('im_presence', $presence);
	}

	function part($room) {
		delete_records('im_presence', 'username', $this->user->username, 'room', $room, 'room_type', 'groupchat');
	}

	function location_update($room) {
		if ($loc = get_record('im_presence', 'username', $this->user->username, 'room_type', 'course')) {
			if ($loc->sesskey != $this->user->sesskey) {
				$loc->sesskey = $this->user->sesskey;
				$loc->first_update = time();
			}

			$loc->room = $room;
			$loc->last_update = time();

			update_record('im_presence', $loc);
		} else {
			$presence = new object();
			$presence->username = $this->user->username;
			$presence->room = $room;
			$presence->room_type = "course";
			$presence->first_update = time();
			$presence->last_update = time();
			$presence->sesskey = $this->user->sesskey;

			insert_record('im_presence', $presence);
		}
	}

	function get_mqueue($msgtype, $channel, $ts) {
		global $CFG, $db;

		// Should rewrite as update_records ?
		begin_sql();
		$q = sprintf("UPDATE %sim_mqueue SET seen=1 WHERE msgtype='%s' AND channel='%s'", $CFG->prefix, $msgtype, $channel);
		$db->Execute($q);
		$records = get_records('im_mqueue', 'seen', 1);
		delete_records('im_mqueue', 'seen', 1);
		commit_sql();

		return $records;
	}

	function get_messages($ts) 
	{
		return $this->get_mqueue("privmsg", $this->user->username, $ts);
	}

	function get_invites($ts) {
		return $this->get_mqueue("invite", $this->user->username, $ts);
	}

	function invite($user, $type, $groupid) {
		$message = new object();
		$message->timestamp = time();
		$message->src = $this->user->username;
		$message->dst = $user;
		$message->seen = 0;
		$message->channel = $user;
		$message->msgtype = "invite";
		$message->msg = json_encode(array("from" => $this->user->username, "type" => $type, "groupid" => $groupid));

		insert_record('im_mqueue', $message);
	}

	function send($src, $dst, $msg) 
	{
		$msg = addslashes($msg); // !!! insert_record does not seem to addslashes() on object memters..
		
		if (eregi("groupchat", $dst)) 
		{
			$this->send_channel($src, $dst, $msg);
		} else 
		{
			$this->send_user($src, $dst, $dst, $msg);
		}
	}

	function send_user($src, $dst, $channel, $msg) {
		$message = new object();
		$message->timestamp = time();
		$message->src = $src;
		$message->dst = $dst;
		$message->seen = 0;
		$message->channel = $channel;
		$message->msgtype = "privmsg";
		$message->msg = $this->findStringUrl($this->remove_tags($msg, "<br /><br>"));

		insert_record('im_mqueue', $message);
	}

	function send_channel($src, $dst, $msg) {
		if ($members = get_records('im_presence', 'room', $dst)) {
			foreach ($members as $m) {
				if ($m->username == $src) continue;
					$this->send_user($src, $dst, $m->username, $msg);
			}
		}
	}

	function get_room($name) {
		$last_update = 0;
		$members = array();
		$room = get_record('im_rooms', 'room', $name);
		if (!$room)
		{
			$room = new object();
			$room->room = $name;
			$room->last_update = time();
			$room->id = insert_record('im_rooms', $room);
			$last_update = $room->last_update;
			error_log("creating new room");
		}

		if ($presence = get_records('im_presence', 'room', $name)) {
			foreach ($presence as $m) {
				if ($m->last_update < time()-15)
				{
					// if last_update is older than 30 seconds we clean out the entries
					delete_records('im_presence', 'id', $m->id); 
					$last_update = time();
					continue;
				}

				if ($m->first_update > $last_update)
					$last_update = $m->first_update;

				error_log("last_update=" . $last_update);
				error_log("m->first_update=" . $m->first_update);

				$members[] = $m->username;
			}
		}
		error_log("room->last_update=" . $room->last_update . " last_update=" . $last_update);

		if ($last_update > $room->last_update)
		{
			$room->last_update = $last_update;
			update_record('im_rooms', $room);
		}

		// we might have to do something ugly here to force the last_update to be new every once in a while
		// to force the roster out as there are hard to reproduce problems with invalid roster information
		// being sent! XXX
		if (time() % 5 == 0)
			$room->last_update = time();
		return array("last_update" => $room->last_update, "members" => $members);
	}
	
	public function remove_tags($string, $allowed_tags = '') {
    	return preg_replace('/\<([a-z]+)\s[a-z=\'"<>:();\s]+\>(.*)<\/\1\>/i', '<\\1>\\2</\\1>', strip_tags($string, $allowed_tags));
	} 
	
	public function findStringUrl($string)
	{
		$regexp = "/((ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?)/i";

		if(!empty($string))
			return preg_replace($regexp, '<a href="$1" target="_blank">$1</a>', $string); 
	}
	
}

// Possibly required for avoiding no-encoding problems with IE
header("Content-Type: text/plain; charset=UTF-8");

if (!isloggedin())
	exit;

$chat = new Chat($USER);

switch ($_REQUEST["type"])
{
	case 'poll':
		if (empty($USER->last_poll)) {
			$USER->last_poll = time();
		}

		$chat->location_update($_GET['room']);
		$room = $chat->get_room($_GET['room']);

		$msg = array();
		$msg['ok'] = 1;

		if ($messages = $chat->get_messages($USER->last_poll)) 
		{
			foreach ($messages as $m) {
				$msg['messages'][] = array("from" => $m->src, "to" => $m->dst, "message" => $chat->findStringUrl($chat->remove_tags($m->msg, "<br /><br>")), "timestamp" => $m->timestamp);
			}
		}

		if ($invites = $chat->get_invites($USER->last_poll)) {
			foreach ($invites as $m) {
				$msg['invites'][] = json_decode($m->msg);
			}
		}

		if ($room["last_update"] >= $USER->last_poll)
			$msg['roster'] = $room['members'];

		$USER->last_poll = time();

		print json_encode($msg);
		break;
	case 'send':
		$msg = json_decode(stripslashes($_GET['msg']));

		foreach ($msg->messages as $m) {
			$chat->send($USER->username, $m->to, $m->message);
		}

		print json_encode(array("ok" => 1, "timestamp" => time()));
		break;
	case 'invite':
		$invite = json_decode(stripslashes($_GET['invite']));

		foreach ($invite->to as $user) {
			$chat->invite($user, $invite->type, $invite->groupid);
		}

		print json_encode(array("ok" => 1, "timestamp" => time(), "type" => $invite->type, "groupid" => $invite->groupid));
		break;
	case 'join':
		$chat->join($_GET['room']);
		print json_encode(array("ok" => 1, "room" => $_GET['room']));
		break;
	case 'part':
		$chat->part($_GET['room']);
		print json_encode(array("ok" => 1));
		break;
}
?>
